package group

import (
	"encoding/json"
	"errors"
	"fmt"
	"server/app/api/request/common"
	group2 "server/app/api/response/group"
	"server/base"
	"server/common/models/group"
	"server/common/models/message"
	"sync"
	"time"
)

var redis_group_id_to_user_ids_expr = 60 * 60 * 12
var redis_group_id_to_user_ids = "group_id_to_user_ids_%d"

var redis_lock = sync.Mutex{}

var GroupDao = new(groupDao)

type groupDao struct{}

func (groupDao) getRedisKey(groupId int64) string {
	return fmt.Sprintf(redis_group_id_to_user_ids, groupId)
}

func (g groupDao) ClearGroupCache(groupId int64) (int64, error) {
	return base.App.Redis.Del(g.getRedisKey(groupId))
}

func (g groupDao) GroupIdToUserIds(groupId int64) ([]int64, error) {
	// redis读取
	var ids []int64
	idsStr, err := base.App.Redis.Get(g.getRedisKey(groupId))
	if err != nil || idsStr == "" {
		// mysql查询需要加锁堵塞，防止缓存击穿
		redis_lock.Lock()
		defer redis_lock.Unlock()

		// mysql查询
		var groupUsers []group.GroupUser
		base.Mysql.Find(&groupUsers, "group_id = ?", groupId)

		// 获取用户ID列表
		ids = make([]int64, len(groupUsers))
		for i, groupUser := range groupUsers {
			ids[i] = groupUser.UserId
		}

		// redis写入
		idsByte, err := json.Marshal(ids)
		if err != nil {
			return []int64{}, err
		}
		_, err = base.App.Redis.Set(g.getRedisKey(groupId), string(idsByte), int64(redis_group_id_to_user_ids_expr))
		if err != nil {
			return []int64{}, err
		}

		// 返回数据
		return ids, nil
	}

	// redis读取
	err = json.Unmarshal([]byte(idsStr), &ids)
	return ids, nil
}

func (g groupDao) JoinGroup(userId int64, groupId int64) error {
	var UserGroup group.GroupUser
	base.Mysql.Find(&UserGroup, "user_id = ? and group_id = ?", userId, groupId)
	if UserGroup.Id == 0 {
		UserGroup = group.GroupUser{UserId: userId, GroupId: groupId, Status: "doing", CreateTime: time.Now().Unix()}
		err := base.Mysql.Create(&UserGroup).Error
		if err != nil {
			return err
		}
		_, err = g.ClearGroupCache(groupId)
		if err != nil {
			return err
		}
	}
	return nil
}

func (g groupDao) LeaveGroup(userId int64, groupId int64) error {
	var UserGroup group.GroupUser
	base.Mysql.Find(&UserGroup, "user_id = ? and group_id = ?", userId, groupId)
	if UserGroup.Id != 0 {
		err := base.Mysql.Delete(&UserGroup).Error
		if err != nil {
			return err
		}
	}

	_, err := g.ClearGroupCache(groupId)
	if err != nil {
		return err
	}
	return nil
}

func (g groupDao) CreateGroup(groupName string) (group.Group, error) {
	Group := group.Group{
		GroupName:  groupName,
		Status:     "doing",
		Detail:     "",
		Head:       "",
		Notice:     "",
		CreateTime: time.Now().Unix(),
		UpdateTime: time.Now().Unix(),
	}
	err := base.Mysql.Create(&Group).Error
	return Group, err
}

func (g groupDao) GetBindGroupByUserId(userId int64) (group.Group, error) {
	var UserGroup group.GroupUser
	base.Mysql.Find(&UserGroup, "user_id = ? and status = 'doing'", userId)
	if UserGroup.Id == 0 {
		return group.Group{}, errors.New("用户未绑定群组")
	}

	var Group group.Group
	base.Mysql.Find(&Group, "id = ?", UserGroup.GroupId)
	return Group, nil
}

func (g groupDao) GetUsersByGroupId(groupId int64) []group.GroupUser {
	var GroupUsers []group.GroupUser
	base.Mysql.Find(&GroupUsers, "group_id = ?", groupId)
	return GroupUsers
}

func (g groupDao) GetGroupMemberList(groupId int64) []group2.GroupMembers {
	var response []group2.GroupMembers
	sql := "select group_users.id,users.id as user_id,users.nickname,users.avatar,users.gender,`rename`,re_head from group_users left join users on group_users.user_id = users.id where group_id = ?"
	base.Mysql.Raw(sql, groupId).Scan(&response)
	return response
}

func (g groupDao) GetGroupMessageList(groupId int64, req common.PageReq) []message.GroupMessage {
	var response []message.GroupMessage
	base.Mysql.Where("group_id = ?", groupId).Where(req.GetPageWhereByLeft("id")).Order("id desc").Limit(req.GetLimit()).Find(&response)

	var list []message.GroupMessage
	for i := len(response) - 1; i >= 0; i-- {
		list = append(list, response[i])
	}
	return list
}
